package com.engine.jucailinkq.attendance.attendanceanalysis.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.*;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.getclockInpoint.biz.AbstractAdjustClockPointAction;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.getclockInpoint.GetClockInPointCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointDTO;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointInfo;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.UtilService;
import com.engine.jucailinkq.attendance.component.persongroup.service.SchedulingResultsService;
import com.engine.jucailinkq.attendance.component.persongroup.service.impl.SchedulingResultsServiceImpl;
import com.engine.jucailinkq.attendance.enums.*;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.ExtensionClassHolder;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import weaver.general.BaseBean;
import weaver.general.Util;

import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class UtilServiceImpl extends Service implements UtilService {
    private SchedulingResultsService schedulingResultsService = ServiceUtil.getService(SchedulingResultsServiceImpl.class);

    /**
     * 获取人员班次信息
     * @param params
     * @return
     */
    @Override
    public Map<String, Object> getSchedulingInFormation(Map<String, Object> params) {
        /** 班次信息*/
        Map<String,Object> schedulingResultsMap = schedulingResultsService.queryDataTableActualUse(params);
        params.put("schedulingResultsMap",schedulingResultsMap);
        return commandExecutor.execute(new GetScheduleResultListCmd(params));
    }

    /**
     * 获取人员在的日期区间内的排班结果
     * @param empIdList 人员id集合
     * @param startDate 开始日期
     * @param endDate 结束日期
     */
    @Override
    public Map<String, List<Map<String, Object>>> getScheduleInfoWithEmpId(List<String> empIdList, String startDate, String endDate) {
        Map<String, List<Map<String, Object>>> scheduleInfo = new HashMap<>();
        Map<String,Object> params = new HashMap<>();
        params.put("tableName", "uf_pbjg");
        params.put("startDate", startDate);
        params.put("endDate", endDate);
        params.put("pblx", "0");
        params.put("current", "1");
        params.put("pageSize", "9999");
        params.put("recurrence", "1");
        for (String empId : empIdList) {
            params.put("pbdx", empId);
            Map<String,Object> schedulingResultsMap = schedulingResultsService.queryDataTableActualUse(params);
            scheduleInfo.put(empId, (List<Map<String, Object>>) schedulingResultsMap.get("data"));
        }
        return scheduleInfo;
    }
    /**
     * 获取人员在的目标日期排班结果中的日期类型
     */
    @Override
    public String getRqlxInScheduleInfo(String empId,String date) {
        Map<String,Object> params = new HashMap<>();
        params.put("tableName", "uf_pbjg");
        params.put("startDate", date);
        params.put("endDate", date);
        params.put("pblx", "0");
        params.put("current", "1");
        params.put("pageSize", "99");
        params.put("recurrence", "1");
        params.put("pbdx", empId);
        Map<String,Object> schedulingResultsMap = schedulingResultsService.queryDataTableActualUse(params);
        List<Map<String, Object>> schedulingData = (List<Map<String, Object>>) schedulingResultsMap.get("data");
        return schedulingData.size() > 0 ? Util.null2String(schedulingData.get(0).get("rqlx")) : "";
    }

    /**
     * 获得打卡数据
     * @param params
     * @return
     */
    @Override
    public List<Map<String, Object>> getClockInTime(Map<String, Object> params) {
        Map<String,Object> result = commandExecutor.execute(new GetClockInTimeListCmd(params));
        List<Map<String, Object>> resultList = (List<Map<String, Object>>)result.get("resultList");
        return resultList;
    }

    @Override
    public void recordItem(Map<String, Object> params) {
        commandExecutor.execute(new RecordDataCmd(params));
    }


    @Override
    public Map<String, Object> getNeedRecordClockInTime(List<ClockPointDTO> clcokInTimeData) {
        Map<String, Object> resultMap = Maps.newHashMap();
        int inIndex = 1;
        int outIndex = 1;
        int jcCloumns = 8;
        for (ClockPointDTO clockPointDTO : clcokInTimeData){
            if (!clockPointDTO.isRecord()){
                continue;
            }

            //当天打卡数据
            Map<String,Object> clcokInTime = clockPointDTO.getClockTime();
            //需要计算的班次打卡时间点
            String pointTime = clockPointDTO.getClassTime();
            //start：开始打卡时间点，end：结束打卡时间点
            ClockPointEnum pointType = clockPointDTO.getPointType();
            //empty:漏卡，equal:打卡时间和班次时间相等，before：打卡时间在班次时间之前，after：打卡时间在班次时间之后
            ClockPointEnum timeType = clockPointDTO.getTimeType();

            if (ClockPointEnum.START.equals(pointType)){
                //开始时间打卡
                if (outIndex-1>inIndex){
                    inIndex = outIndex;
                }
                String key = "j"+inIndex;
                String ckey = "c"+inIndex;
                if (!ClockPointEnum.EMPTY.equals(timeType) && clcokInTime != null){
                    String time = clcokInTime.get("signdate")+" "+clcokInTime.get("signtime");
                    String value = time;

                    String ctime = Util.null2String(resultMap.get(ckey));
                    if (ctime !=null && !ctime.equals("NULL") && !"".equals(ctime)){
                        if (DateUtil.getTime(value).compareTo(DateUtil.getTime(ctime)) > 0){
                            resultMap.put(key,"NULL");
                            inIndex++;
                            key = "j"+inIndex;
                        }
                    }
                    resultMap.put(key,value);
                }else {
                    resultMap.put(key,"NULL");
                }
                inIndex++;
            }else if (ClockPointEnum.END.equals(pointType)){

                //结束时间打卡
                if (inIndex-1>outIndex){
                    outIndex = inIndex-1;
                }
                String key = "c"+outIndex;
                String jkey = "j"+inIndex;
                if (!ClockPointEnum.EMPTY.equals(timeType) && clcokInTime != null){
                    String time = clcokInTime.get("signdate")+" "+clcokInTime.get("signtime");
                    String value = time;
                    String jtime = Util.null2String(resultMap.get(jkey));
                    if (jtime !=null && !jtime.equals("NULL") && !"".equals(jtime)){
                        if (DateUtil.getTime(value).compareTo(DateUtil.getTime(jtime)) < 0){
                            resultMap.put(key,"NULL");
                            outIndex++;
                            key = "c"+outIndex;
                        }
                    }
                    resultMap.put(key,value);
                }else {
                    resultMap.put(key,"NULL");
                }
                outIndex++;
            }

        }
        for (int i=1;i<=8;i++){
            String jkey = "j"+i;
            String ckey = "c"+i;
            if (resultMap.get(jkey) == null){
                resultMap.put(jkey,"NULL");
            }
            if (resultMap.get(ckey) == null){
                resultMap.put(ckey,"NULL");
            }
        }
        return resultMap;
    }

    /**
     * 获取打卡卡点
     * @param params
     * @return
     */
    @Override
    public List<ClockPointDTO> getClockInPointCmd(Map<String,Object> params) {
        List<Map<String, Object>> scheduleResult = (List<Map<String, Object>>) params.get("scheduleResult");

        Map<String,Object> resultMap = commandExecutor.execute(new GetClockInPointCmd(params));

        List<Map<String, Object>> newscheduleResult = (List<Map<String, Object>>)resultMap.get("scheduleResult");
        List<Map<String, Object>> askForLeaveAndEvctionScheduleList = (List<Map<String, Object>>)resultMap.get("askForLeaveAndEvctionScheduleList");
        params.putAll(resultMap);
//        resultMap = commandExecutor.execute(new AdjustByWorkOverTimeCmd(params));
        List<ClockPointDTO> clcokInPointList = (List<ClockPointDTO>)resultMap.get("clcokInPointList");
        if (!scheduleResult.equals(newscheduleResult)){
            scheduleResult.removeAll(scheduleResult);
            scheduleResult.addAll(newscheduleResult);
        }
        clcokInPointList = clcokInPointList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.getClassTime()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

        ClockPointInfo clockPointInfo = ClockPointInfo.builder().analysisDate(Util.null2String(params.get("analysisDate"))).clcokInPointList(clcokInPointList)
                .scheduleResult(newscheduleResult).askForLeaveAndEvctionScheduleList(askForLeaveAndEvctionScheduleList).clockInTimeList((List<Map<String, Object>>) params.get("clockInTimeList")).build();
        List<AbstractAdjustClockPointAction> adjustClockPointActionList = ExtensionClassHolder.getAdjustClockPointAction();
        for (AbstractAdjustClockPointAction action:adjustClockPointActionList){
            //适用班次
            String applyClass = action.getApplyClasses();
            if (applyClass != null && !"".equals(applyClass) && scheduleResult.size() > 0){
                String bcxx = Util.null2String(scheduleResult.get(0).get("bcxx"));
                List<String> applyClassList = Lists.newArrayList(applyClass.split(","));
                if (!applyClassList.contains(bcxx)){
                    continue;
                }
            }
            List<ClockPointDTO> clockPointDTOS = action.execute(clockPointInfo);
            clockPointInfo.setClcokInPointList(clockPointDTOS);
        }
        log.debug("after adjustClockPointAction : [{}]",clockPointInfo.getClcokInPointList());

        return clockPointInfo.getClcokInPointList();
    }

    /**
     * 计算出勤时长
     * @param params
     * @return
     */
    @Override
    public double computeAttendanceDuration(Map<String, Object> params) {
        Map<String,Object> resultMap = commandExecutor.execute(new ComputeAttendanceDurationCmd(params));
        return Double.valueOf(resultMap.get("attendanceDuration").toString());
    }
    /**
     * 根据人员集合获得对应需要分析的日期
     * @param params
     * @return
     */
    @Override
    public Map<String, Object> getAttendanceCycle(Map<String, Object> params) {
        return commandExecutor.execute(new GetAttendanceCycleCmd(params));
    }
}
